Skip to content

Adopt default main actor isolation and drop CocoaPods - #55

Closed
jmarek41 wants to merge 1 commit into
mainfrom
feature/default-main-actor-isolation
Closed

Adopt default main actor isolation and drop CocoaPods#55
jmarek41 wants to merge 1 commit into
mainfrom
feature/default-main-actor-isolation

Conversation

@jmarek41

Copy link
Copy Markdown
Member

Alternative to #54.

Motivation

#54 isolates CellKit's UIKit-facing API to the main actor by annotating each declaration with @MainActor. The goal is right — CellKit is a UITableView/UICollectionView data source layer and every one of its protocols is only ever exercised on the main thread — but Swift 6.2 ships a setting built exactly for this (SE-0466), and Apple's WWDC25 guidance points UI-focused modules at it directly.

Change

defaultIsolation set to MainActor plus the Swift 6 language mode on both targets:

let swiftSettings: [SwiftSetting] = [
    .swiftLanguageMode(.v6),
    .defaultIsolation(MainActor.self),
    .enableUpcomingFeature("NonisolatedNonsendingByDefault"),
    .enableUpcomingFeature("InferIsolatedConformances")
]

Zero @MainActor annotations in the library sources. The only Sources/ changes are removals: redundant @available(iOS 13.0, tvOS 13.0, *), #if SWIFT_PACKAGE guards, and two long-standing SwiftLint violations.

Notably it also needs no rework of DifferentiableCellModelWrapper — no MainActor.assumeIsolated, no eagerly stored differenceIdentifier. Under SE-0470 the wrapper's Equatable/Differentiable conformances become main actor-isolated and DifferenceKit's nonisolated generic algorithm accepts them, because it is called from the main actor.

Other changes:

  • Platforms → iOS 15 / tvOS 15, matching FTAPIKit.
  • CocoaPods removed in favour of the Swift package (CellKit.podspec, Gemfile, Gemfile.lock). The podspec could not express defaultIsolation without duplicating it as SWIFT_DEFAULT_ACTOR_ISOLATION in pod_target_xcconfig, which would leave two distribution channels able to drift apart on the public concurrency contract.
  • Example app moved to the Swift 6 language mode with default main actor isolation and approachable concurrency, matching how our apps are configured.
  • CI rewritten to match FTAPIKit's ci.yml: no pod lib lint, actions/checkout@v6, and a build of both library schemes plus the Example app. swiftlint --strict now passes — it did not on main.

Consumer impact

Verified against a real consumer module compiled in the Swift 6 language mode:

Consumer module Annotations needed
Default nonisolated isolation none
Default MainActor isolation @MainActor on the conformance

The first row is the case #54 was written for — the 45 hand-written @MainActor conformances and the @preconcurrency import all become unnecessary.

The second row is a rough edge in conformance isolation inference: it is not inferred through inherited protocol requirements even with InferIsolatedConformances enabled. It is not introduced by this PRmain already requires an annotation there today. Both cases are documented in the README, and the Example app demonstrates the second.

Verification

  • xcodebuild build succeeds for CellKit and DiffableCellKit on generic/platform=iOS with zero warnings, in the Swift 6 language mode.
  • Example app builds clean (aside from pre-existing UITableViewRowAction deprecations in its own code).
  • swiftlint --strict: 0 violations.

Tested with Xcode 26.6 / Swift 6.3.3.

Breaking

Source-breaking for any conformance that is not main actor-isolated, and the platform floor moves to iOS 15 / tvOS 15 with Xcode 26+ required to build. Warrants a 1.0.0 tag — the README already points at from: "1.0.0", so that tag needs cutting before this is announced.

🤖 Generated with Claude Code

Set `defaultIsolation` to `MainActor` and the Swift 6 language mode for
both targets, which makes the whole UIKit-facing API main actor-isolated
without a single annotation in the library sources.

Platforms move to iOS 15 / tvOS 15 to match FTAPIKit, which makes the
`@available(iOS 13.0, tvOS 13.0, *)` annotations redundant.

CocoaPods support is removed in favour of the Swift package, so the
`#if SWIFT_PACKAGE` guards around `import CellKit` go away too.

The Example app is updated to the Swift 6 language mode with default main
actor isolation and approachable concurrency, matching how apps consuming
CellKit are configured.

CI is rewritten to match FTAPIKit: no `pod lib lint`, current runner
actions, and a build of both library schemes plus the Example app. The two
long-standing SwiftLint violations in DataSource.swift are fixed so
`swiftlint --strict` passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jmarek41
jmarek41 requested a review from a team as a code owner August 15, 2026 18:27
@jmarek41

Copy link
Copy Markdown
Member Author

Closing for now — keeping the work on the branch while we settle the approach.

@jmarek41 jmarek41 closed this Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant